/* -------------------------------------------------------------------------
 *
 * pgstat_subscription.c
 *	  订阅统计的实现。
 *
 * 本文件包含订阅统计的实现。它与pgstat.c保持分开，以便区分统计访问/
 * 存储实现与个别统计类型的详细信息。
 *
 * Copyright (c) 2001-2022, PostgreSQL Global Development Group
 *
 * IDENTIFICATION
 *	  src/backend/utils/activity/pgstat_subscription.c
 * -------------------------------------------------------------------------
 */

#include "postgres.h"

#include "utils/pgstat_internal.h"


/*
 * 报告订阅错误。
 */
void pgstat_report_subscription_error(Oid fc_subid, bool fc_is_apply_error)
{
	PgStat_EntryRef *fc_entry_ref;
	PgStat_BackendSubEntry *fc_pending;

	fc_entry_ref = pgstat_prep_pending_entry(PGSTAT_KIND_SUBSCRIPTION,
										  InvalidOid, fc_subid, NULL);
	fc_pending = fc_entry_ref->pending;

	if (fc_is_apply_error)
		fc_pending->apply_error_count++;
	else
		fc_pending->sync_error_count++;
}

/*
 * 报告创建订阅。
 *
 * 确保在事务回滚时统计信息被丢弃。
 */
void pgstat_create_subscription(Oid fc_subid)
{
	pgstat_create_transactional(PGSTAT_KIND_SUBSCRIPTION,
								InvalidOid, fc_subid);
}

/*
 * 报告删除订阅。
 *
 * 确保在事务提交时统计信息被丢弃。
 */
void pgstat_drop_subscription(Oid fc_subid)
{
	pgstat_drop_transactional(PGSTAT_KIND_SUBSCRIPTION,
							  InvalidOid, fc_subid);
}

/*
 * SQL可调用的pgstat*函数的支持函数。返回
 * 一个订阅的收集统计信息或NULL。
 */
PgStat_StatSubEntry *
pgstat_fetch_stat_subscription(Oid fc_subid)
{
	return (PgStat_StatSubEntry *)
		pgstat_fetch_entry(PGSTAT_KIND_SUBSCRIPTION, InvalidOid, fc_subid);
}

/*
 * 刷新条目的待处理统计信息
 *
 * 如果 nowait 为真，如果无法立即获取锁，则该函数返回 false，
 * 否则返回 true。
 */
bool pgstat_subscription_flush_cb(PgStat_EntryRef *fc_entry_ref, bool fc_nowait)
{
	PgStat_BackendSubEntry *fc_localent;
	PgStatShared_Subscription *fc_shsubent;

	fc_localent = (PgStat_BackendSubEntry *) fc_entry_ref->pending;
	fc_shsubent = (PgStatShared_Subscription *) fc_entry_ref->shared_stats;

	/* localent 始终具有非零内容 */

	if (!pgstat_lock_entry(fc_entry_ref, fc_nowait))
		return false;

#define SUB_ACC(fld) fc_shsubent->stats.fld += fc_localent->fld
	SUB_ACC(apply_error_count);
	SUB_ACC(sync_error_count);
#undef SUB_ACC

	pgstat_unlock_entry(fc_entry_ref);
	return true;
}

void pgstat_subscription_reset_timestamp_cb(PgStatShared_Common *fc_header, TimestampTz fc_ts)
{
	((PgStatShared_Subscription *) fc_header)->stats.stat_reset_timestamp = fc_ts;
}
